package com.example.graduation.util;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * ProjectName graduation
 *
 * @author xieyucan
 * <br>CreateDate 2022/2/11 15:04
 */
@Component
public class JwtUtil {

    @Value("${jwt.expire}")
    private int expire;

    @Value("${jwt.secret}")
    private String secret;


    /**
     * 创建token
     *
     * @param userId
     * @return
     */
    public String createToken(int userId) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        DateTime offset = DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, expire);

        /**
         * 从他的底层可以看出，JWTCreator需要创建出builder（可以生成token的构造器）
         * 然而他却没有，后来，在JWT类中发现，JWT.create()可以生成builder
         * withClaim的解释是（添加自定义索赔值。）对此，我可以在下一个函数中通过这个突破口获取我填进去的值
         * @param userId
         * @return {@link String}
         * @author xieyucan
         * CreateDate 2022/2/11 15:40
         */
        JWTCreator.Builder builder = JWT.create();
        String token = builder.withClaim("userId", userId).withExpiresAt(offset).sign(algorithm);

        return token;
    }


    /**
     * 从token中获取我之前创建token时，设置进去的索赔值
     * 在这里我使用的是userId
     *
     * @param token
     * @return
     */
    public int getUserIdByToken(String token) {
        DecodedJWT decode = JWT.decode(token);
        Integer userId = decode.getClaim("userId").asInt();
        return userId;
    }


    /**
     * 判断token是否有效，
     * 在这里我为什么没有返回值呢，因为当我判断token无效时，我就会抛出异常，
     * 对此，我可以在使用他的时候，我用try，catch包裹他，这样当token无效时，我可以设置自己的逻辑
     *
     * @param token
     */
    public void verifier(String token) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        /**
         * 源码中说这样可以返回一个@return a new JWTVerifier instance.（JWTVerifier实例对象）
         */
        JWTVerifier build = JWT.require(algorithm).build();
        build.verify(token);

    }

}
